package org.sjsu.freedoor.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.sjsu.freedoor.util.Utilities;

public class ServiceList {
	public final static String SERVICES_ARRAY_KEY = "services";
	
	private HashMap<String,HashMap<String, Service>> m_map; //map of services with unique <community_url,id> constraint
	
	public ServiceList() {
		m_map = new HashMap<String,HashMap<String, Service>>();
	}
	
	public int size() {
		return getList().size();
	}
	
	public boolean loadServices(JSONArray jsonArr) {
		m_map.clear();
		
		try {
			for (int i = 0; i < jsonArr.length(); i++) {
				Service s = new Service();
				if(s.loadService(jsonArr.getJSONObject(i)))
					putService(s);
			}
		} catch (JSONException e) {
			System.out.println("Invalid ServiceList jsonArray: " + jsonArr.toString());
			return false;
		}
		
		return true;
	}
	
	public boolean loadServices(JSONObject jsonObj) {
		try {
			JSONArray arr = jsonObj.getJSONArray(SERVICES_ARRAY_KEY);
			return loadServices(arr);
		} catch (JSONException e) {
//			try {
				Service s = new Service();
				if(s.loadService(jsonObj))
					return putService(s);
				else
					return false;
//			} catch (JSONException e2) {
//				System.out.println("Invalid ServiceList jsonObject: " + jsonObj.toString());
//				return false;
//			}
		}
	}
	
	public boolean loadServices(String jsonString) {
		try {
			JSONObject jsonObj = new JSONObject(jsonString);
			return loadServices(jsonObj);
		} catch (JSONException e) {
			// might be json array
			try {
				JSONArray jsonArr = new JSONArray(jsonString);
				return loadServices(jsonArr);
			} catch (JSONException e2) {
				System.out.println("Invalid ServiceList jsonString: " + jsonString.toString());
				return false;
			}
		}
	}
	
	public String toJsonString(boolean encapsulateWithCurlyBraces, boolean useListKey)
	{
		StringBuilder str = new StringBuilder();
		if(encapsulateWithCurlyBraces)
			str.append("{");
		if(useListKey || encapsulateWithCurlyBraces)
			str.append("\"" + SERVICES_ARRAY_KEY + "\":");
		str.append("[");
		
		for(HashMap<String, Service> nodeServiceMap : m_map.values())
			for(Service s : nodeServiceMap.values())
				str.append(s.toJsonString() + ",");
		if(m_map.size() > 0)
			str.deleteCharAt(str.length()-1);
		
		str.append("]");
		if(encapsulateWithCurlyBraces)
			str.append("}");
		
		return str.toString();
	}
	
	public JSONObject toJsonObject()
	{
		return Utilities.toJsonObject(this.toJsonString(true, true));
	}
	
	public JSONArray toJsonArray()
	{
		return Utilities.toJsonArray(this.toJsonString(false, false));
	}
	
	public boolean add(Service service) {
		return putService(service);
	}
	
	public Collection<Service> getList() {
		Collection<Service> list = new ArrayList<Service>();
		for(HashMap<String, Service> nodeServiceMap : m_map.values())
			for(Service s : nodeServiceMap.values())
				list.add(s);
		return list;
	}
	
	private boolean putService(Service srv) {
		//no validation for duplicate <url, id> tuples done here
		if(!m_map.containsKey(srv.getURL()))
			m_map.put(srv.getURL(), new HashMap<String, Service>());
		
		if(srv.getId().isEmpty())
			m_map.get(srv.getURL()).put(String.valueOf(m_map.get(srv.getURL()).keySet().size()), srv); //for new, local items allow duplicate URL/ID tuples (since ID is blank)
		else
			m_map.get(srv.getURL()).put(srv.getId(), srv);
		
		return true;
	}

	public void removeForeignServices(String localUrl) {
		HashMap<String, HashMap<String, Service>> newMap = new HashMap<String, HashMap<String, Service>>();
		if(m_map.containsKey(localUrl))
			newMap.put(localUrl, m_map.get(localUrl));
		m_map = newMap;
	}
	
	public void configureAllServicesForNewLocalInsertion(String localUrl) {
		Collection<Service> services = getList();
		m_map.clear();
		for(Service s : services) {
			s.setId("");
			s.setURL(localUrl);
			putService(s);
		}
	}
}
